package com.example.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.example.common.Constants;
import com.example.entity.*;
import com.example.exception.CustomException;
import com.example.mapper.OutgoingDocMapper;
import com.example.utils.TokenUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OutgoingDocService {
    @Resource
    private OutgoingDocMapper outgoingDocMapper;
    @Resource
    private FlowObjectService flowObjectService; // 流转对象服务
    @Resource
    private OutgoingOpinionService outgoingOpinionService;
    @Resource
    private AttachmentService attachmentService; // 附件服务
    @Resource
    private RecordNoService recordNoService;


    @Transactional(rollbackFor = Exception.class)
    public void add(OutgoingDoc doc) {
        if (ObjectUtil.isEmpty(doc.getTitle())) {
            throw new CustomException("5011", "文件标题不能为空");
        }
        if (ObjectUtil.isEmpty(doc.getSenderOrg())) {
            throw new CustomException("5012", "发文单位不能为空");
        }
        if (ObjectUtil.isNotEmpty(doc.getSenderDocNo())) {
            OutgoingDoc existDoc = outgoingDocMapper.selectBySenderDocNo(doc.getSenderDocNo());
            if (existDoc != null) {
                throw new CustomException("5014", "发文编号已存在");
            }
        }

        System.out.println(doc);

        doc.setArchiveStatus("未处理");
        doc.setCreator(TokenUtils.getCurrentUser().getId());
        doc.setSecretType(doc.getSecretType() != null ? doc.getSecretType() : 0);  // 默认普通件
        doc.setProcessType(doc.getProcessType());
        doc.setStatus(doc.getStatus() != null ? doc.getStatus() : Constants.STATUS_PENDING);
        doc.setFeedbackRequired(doc.getFeedbackRequired() != null ? doc.getFeedbackRequired() : false);
        if (ObjectUtil.isNotEmpty(doc.getFileList())) {
            String attachmentId = doc.getFileList().stream().map(Attachment::getUid).collect(Collectors.joining(","));
            doc.setAttachmentId(attachmentId);
        }

        outgoingDocMapper.insert(doc);

        Integer id = doc.getId();

        // 处理附件 - 增加空值检查
        List<Attachment> fileList = doc.getFileList();
        if (fileList != null && fileList.size() > 0) {
            for (Attachment file : fileList) {
                Attachment attachment = new Attachment();
                attachment.setId(file.getUid());
                attachment.setFileName(file.getFileName());
                attachment.setFileType("发文附件");
                attachment.setFilePath(file.getFilePath());
                attachment.setCreateDate(new Date());
                attachment.setCreator(TokenUtils.getCurrentUser().getId());
                attachment.setDocId(id);
                // 保存附件信息
                attachmentService.save(attachment);
            }
        }

        // 查询level=0的办公室流转对象
        List<FlowObject> officeObjects = flowObjectService.selectByLevel(0);
        FlowObject office = officeObjects.get(0); // 只有一个办公室

        // 构造拟办意见对象
        OutgoingOpinion opinion = new OutgoingOpinion();
        opinion.setDocId(id);                // 收文id
        opinion.setObjectId(office.getId());    // 办公室流转对象id
        opinion.setName(office.getName());
        opinion.setPosition(office.getPosition());
        opinion.setLevel(office.getLevel());
        opinion.setOpinion(doc.getOpinion());    // 前端输入的拟办意见
        opinion.setNextObjectId(null);           // 无下一流转对象
        opinion.setOpinionType("拟办意见");       // 意见类型
        opinion.setCreator(TokenUtils.getCurrentUser().getId()); // 当前用户id
        opinion.setCreateDate(new Date());       // 创建时间

        // 保存拟办意见
        outgoingOpinionService.save(opinion);
    }

    /**
     * 根据ID删除发文
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Integer id) {
        OutgoingDoc doc = outgoingDocMapper.selectById(id); // 检查文档存在性
        outgoingDocMapper.deleteById(id);
    }

    /**
     * 批量删除发文
     */
    public void deleteBatch(List<Integer> ids) {
        for (Integer id : ids) {
            deleteById(id);
        }
    }

    /**
     * 更新发文信息（禁止修改已存档文档）
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateById(OutgoingDoc doc) {
        OutgoingDoc existDoc = outgoingDocMapper.selectById(doc.getId());

        if (Constants.STATUS_ARCHIVED.equals(existDoc.getStatus())) {
            throw new CustomException("5015", "已存档文档不可修改");
        }

        // 拷贝更新字段（避免直接操作参数对象，防止脏数据）
        existDoc.setSenderOrg(doc.getSenderOrg());
        existDoc.setSecretLevel(doc.getSecretLevel());
        existDoc.setPageCount(doc.getPageCount());
        existDoc.setTitle(doc.getTitle());
        existDoc.setFileNo(doc.getFileNo());
        existDoc.setSenderDocNo(doc.getSenderDocNo());
        existDoc.setProcessType(doc.getProcessType());
        existDoc.setHandlingOrg(doc.getHandlingOrg());
        existDoc.setAttachmentId(doc.getAttachmentId());
        existDoc.setUpdater(TokenUtils.getCurrentUser().getId());
        existDoc.setUpdateDate(new Date());
        existDoc.setSecretType(doc.getSecretType());
        existDoc.setStatus(doc.getStatus());
        existDoc.setLimitDate(doc.getLimitDate());
        existDoc.setUrgencyLevel(doc.getUrgencyLevel());
        existDoc.setCreateDate(doc.getCreateDate());
        existDoc.setFeedbackRequired(doc.getFeedbackRequired());

        outgoingDocMapper.updateById(existDoc);
    }

    public void updateStatusById(OutgoingDoc doc) {
        OutgoingDoc existDoc = outgoingDocMapper.selectById(doc.getId());

        if (Constants.STATUS_ARCHIVED.equals(existDoc.getStatus())) {
            throw new CustomException("5015", "已存档文档不可修改");
        }

        // 拷贝更新字段（避免直接操作参数对象，防止脏数据）
        existDoc.setStatus(1);
        existDoc.setArchiveStatus(Constants.PROCESS_TYPE_PROCESSING);

        outgoingDocMapper.updateById(existDoc);
    }

    /**
     * 根据ID查询发文（含流转意见）
     */
    public OutgoingDoc getWithOpinions(Integer id) {
        OutgoingDoc doc = outgoingDocMapper.selectById(id);
        if (doc == null) {
            throw new CustomException("5016", "发文不存在");
        }
        // 关联查询流转意见（调用Mapper的selectOpinionsByDocId）
        List<OutgoingOpinion> opinions = outgoingDocMapper.selectOpinionsByDocId(id);
        doc.setOpinions(opinions);
        return doc;
    }

    /**
     * 分页查询发文列表（使用Mapper的XML动态查询）
     */
    public PageInfo<OutgoingDoc> selectPage(OutgoingDoc query, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize); // 启动分页
        // 直接调用Mapper的selectPageList（XML实现动态条件）
        List<OutgoingDoc> list = outgoingDocMapper.selectPageList(query);
        return PageInfo.of(list);
    }

    /**
     * 发文存档
     */
    @Transactional(rollbackFor = Exception.class)
    public void archive(Integer id) {
        OutgoingDoc doc = outgoingDocMapper.selectById(id);
//        String recordNo = recordNoService.getRecordNo("fw");
        String recordNo = "fw" + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + "_" + UUID.randomUUID().toString().substring(0, 4);

        if (Constants.STATUS_ARCHIVED.equals(doc.getStatus())) {
            throw new CustomException("5016", "文档已存档，无需重复操作");
        }
        // 获取当前年份
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        int secretType = doc.getSecretType();
        // 查询当前年份的最大文件编号
        String maxFileNo = outgoingDocMapper.selectMaxFileNoByYear(currentYear, secretType);
        int nextNo = 1; // 默认从0001开始
        if (maxFileNo != null) {
            try {
                nextNo = Integer.parseInt(maxFileNo) + 1;
            } catch (NumberFormatException e) {
                throw new CustomException("5017", "文件编号格式异常");
            }
            // 检查编号是否超过9999
            if (nextNo > 9999) {
                throw new CustomException("5015", "当前年份文件编号已达上限");
            }
        }
        // 生成4位数字编号（不足补零）
        String fileNo = String.format("%04d", nextNo);
        doc.setFileNo(Integer.valueOf(fileNo));
        doc.setStatus(2);
        doc.setArchiveStatus(Constants.PROCESS_TYPE_ARCHIVED);
        doc.setArchiveDate(new Date());
        doc.setRecordNo(recordNo);
        doc.setUpdater(TokenUtils.getCurrentUser().getId());
        outgoingDocMapper.updateById(doc);
    }

    /**
     * 获取所有流转对象
     */
    public List<FlowObject> getAllFlowObjects() {
        List<FlowObject> list = flowObjectService.selectAll();
        if (ObjectUtil.isEmpty(list)) {
            throw new CustomException("5017", "未配置流转对象");
        }
        return list;
    }

    public List<OutgoingDoc> getDocsWithLimitDate() {
        List<OutgoingDoc> list = outgoingDocMapper.selectAllWithLimitDate();
        return list;
    }

    public PageInfo<OutgoingDoc> selectNotArchivePage(OutgoingDoc query, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<OutgoingDoc> list = outgoingDocMapper.selectNotArchivePage(query);
        return PageInfo.of(list);
    }

    public PageInfo<OutgoingDoc> selectHistoryPage(OutgoingDoc query, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<OutgoingDoc> list = outgoingDocMapper.selectHistoryPage(query);
        return PageInfo.of(list);
    }

    @Transactional(rollbackFor = Exception.class)
    public List<ArchiveResult> batchArchive(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }

        // 1. 获取所有待存档文档（按ID排序保证一致性）
        List<OutgoingDoc> docs = outgoingDocMapper.selectBatchIdsOrdered(ids);
        if (docs.size() != ids.size()) {
            throw new CustomException("5020", "部分文档不存在");
        }

        // 2. 检查是否已存档并分组（按年份+密级）
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        Map<String, List<OutgoingDoc>> groupMap = new TreeMap<>(); // TreeMap保证顺序一致

        for (OutgoingDoc doc : docs) {
            if (Constants.PROCESS_TYPE_ARCHIVED.equals(doc.getArchiveStatus())) {
                throw new CustomException("5016", "文档(ID=" + doc.getId() + ")已存档");
            }
            String groupKey = currentYear + "_" + doc.getSecretType();
            groupMap.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(doc);
        }

        // 3. 为每个分组分配连续件号
        List<ArchiveResult> results = new ArrayList<>();
        for (Map.Entry<String, List<OutgoingDoc>> entry : groupMap.entrySet()) {
            String[] keys = entry.getKey().split("_");
            int year = Integer.parseInt(keys[0]);
            int secretType = Integer.parseInt(keys[1]);
            List<OutgoingDoc> groupDocs = entry.getValue();

            // 获取分组锁并分配件号
            assignFileNumbers(year, secretType, groupDocs, results);
        }

        return results;
    }

    private void assignFileNumbers(int year, int secretType,
                                   List<OutgoingDoc> groupDocs,
                                   List<ArchiveResult> results) {
        // 使用数据库行锁锁定计数器
        FileNoCounter counter = outgoingDocMapper.selectCounterForUpdate(year, secretType, "发文");
        if (counter == null) {
            counter = new FileNoCounter(year, secretType, 0, "发文");
            outgoingDocMapper.insertCounter(counter);
        }

        int nextNo = counter.getLastNo() + 1;

        // 检查编号容量
        if (nextNo + groupDocs.size() - 1 > 9999) {
            throw new CustomException("5015", "密级类型[" + secretType + "]编号已达上限");
        }

        // 分配连续件号
        for (OutgoingDoc doc : groupDocs) {
            try {
                // 生成件号并更新文档
                String fileNo = String.format("%04d", nextNo++);
                doc.setFileNo(Integer.valueOf(fileNo));
                doc.setRecordNo(generateRecordNo());
                updateDocStatus(doc);

                // 记录成功结果
                results.add(new ArchiveResult(doc.getId(), true, fileNo, ""));
            } catch (Exception e) {
                // 记录失败结果
                results.add(new ArchiveResult(
                        doc.getId(),
                        false,
                        "",
                        e instanceof CustomException ? e.getMessage() : "系统错误"
                ));
            }
        }

        // 更新计数器
        counter.setLastNo(nextNo - 1);
        outgoingDocMapper.updateCounter(counter);
    }

    private String generateRecordNo() {
        return "sw_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + "_"
                + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
    }

    private void updateDocStatus(OutgoingDoc doc) {
        doc.setStatus(2);
        doc.setArchiveStatus(Constants.PROCESS_TYPE_ARCHIVED);
        doc.setArchiveDate(new Date());
        doc.setUpdater(TokenUtils.getCurrentUser().getId());
        outgoingDocMapper.updateById(doc);
    }
}
